Skip to main content
IBM Quantum Platform

SparseObservable

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

GitHub

Bases: object

Um observável sobre bases Pauli que armazena seus dados em um formato qubit-esparso.


matemática

Esse observável representa uma soma sobre cadeias de operadores de Pauli e projetores de estado próprio de Pauli, com cada termo ponderado por algum número complexo. Ou seja, o observável completo é

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

para números complexos cic_i e operadores de um único qubit atuando no qubit nn de um alfabeto restrito Ai(n)A^{(n)}_i. A soma sobre ii é a soma dos termos individuais, e o produto tensorial produz as cadeias de operadores.

O alfabeto de operadores de um único qubit permitido do qual o Ai(n)A^{(n)}_i é extraído são os operadores de Pauli e os operadores de projeção de estado próprio de Pauli. Explicitamente, são eles:

Rótulo
Operador
Valor numérico
BitTerm atributo
"I"II (identidade)Não armazenado.Não armazenado.
"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 (projetor para o estado próprio positivo de X)0b1010 (10)PLUS
"-"\lvert-\rangle\langle-\rvert (projetor para o estado próprio negativo de X)0b0110 (6)MINUS
"r"rr\lvert r\rangle\langle r\rvert (projetor para o estado próprio positivo de Y)0b1011 (11)RIGHT
"l"ll\lvert l\rangle\langle l\rvert (projetor para o estado próprio negativo de Y)0b0111 (7)LEFT
"0"00\lvert0\rangle\langle0\rvert (projetor para o estado próprio positivo de Z)0b1001 (9)ZERO
"1"11\lvert1\rangle\langle1\rvert (projetor para o estado próprio negativo de Z)0b0101 (5)ONE

O alfabeto permitido forma uma base supercompleta do espaço do operador. Isso significa que não há um somatório único para representar um determinado observável. Em comparação, SparsePauliOp usa uma base precisa do espaço do operador, portanto (depois de combinar termos da mesma cadeia de Pauli, remover zeros e classificar os termos em alguma ordem canônica ) há apenas uma representação de qualquer operador.

SparseObservable usa sua base particular supercompleta com o objetivo de tornar a "eficiência da medição" equivalente à "eficiência da representação". Por exemplo, o observável 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} pode ser medido com eficiência no hardware com medições simples ZZ, mas só pode ser representado por SparsePauliOp como (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, o que requer termos armazenados em 2n2^n. SparseObservable requer apenas um único termo para armazenar isso.

A desvantagem disso é que não é prático pegar uma matriz arbitrária ou SparsePauliOp e encontrar a melhor SparseObservable representação. Normalmente, você desejará construir um SparseObservable diretamente, em vez de tentar decompor em um.


Representação

A representação interna de a SparseObservable armazena apenas os operadores de qubit não idênticos. Isso torna significativamente mais eficiente a representação de observáveis, como nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; SparseObservable requer uma quantidade de memória linear no número total de qubits, enquanto SparsePauliOp é escalonado quadraticamente.

Os termos são armazenados compactados, com espírito semelhante ao formato de linha esparsa compactada de matrizes esparsas. Nessa analogia, os termos da soma são as "linhas", e os termos do qubit são as "colunas", em que uma entrada ausente representa a identidade em vez de um zero. De forma mais explícita, a representação é composta por quatro matrizes contíguas:

Atributo
Duração
Descrição
coeffsttO multiplicador escalar complexo para cada termo.
bit_termsssCada um dos termos de um único qubit sem identidade para todos os operadores, em ordem. Elas correspondem à não identidade Ai(n)A^{(n)}_i na descrição da soma, em que as entradas são armazenadas na ordem crescente de ii primeiro, e na ordem crescente de nn dentro de cada termo.
indicesssO qubit correspondente ( nn ) para cada um dos operadores em bit_terms. SparseObservable exige que essa lista seja classificada por termos, e os algoritmos podem contar com a manutenção desse invariante.
boundariest+1t+1Os índices que dividem bit_terms e indices em termos completos. Para o termo número ii, seu coeficiente complexo é coeffs[i], e seus operadores de qubit único não idênticos e seus qubits correspondentes são a fatia boundaries[i] : boundaries[i+1] em bit_terms e indices respectivamente. boundaries sempre tem um 0 explícito como seu primeiro elemento.

O parâmetro de comprimento tt é o número de termos na soma, e o parâmetro ss é o número total de termos de um único qubit sem identidade.

Como exemplos ilustrativos:

  • no caso de um operador zero, boundaries tem comprimento 1 (um único 0) e todos os outros vetores são vazios.
  • no caso de um operador de identidade totalmente simplificado, boundaries é [0, 0], coeffs tem uma única entrada, e bit_terms e indices estão vazios.
  • para o operador 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]. O operador pode atuar em mais de quatro qubits, dependendo do parâmetro num_qubits parâmetro. Os bit_terms são valores inteiros, cujos números mágicos podem ser acessados por meio da classe de atributo BitTerm classe de atributo. Observe que os termos e índices de um único bit são classificados em ordem ordenada termwise. Esse é um requisito da aula.

Esses casos não são especiais, são totalmente consistentes com as regras e não devem precisar de tratamento especial.

O item escalar da matriz bit_terms é armazenado como um byte numérico. Os valores numéricos estão relacionados à representação Pauli simétrica que SparsePauliOp usa, e podem ser acessados com acesso nomeado por uma enumeração:

BitTerm

class BitTerm

GitHub

Um IntEnum que fornece acesso nomeado aos valores numéricos usados para representar cada um dos termos do alfabeto de qubit único enumerados em Alfabeto de termos de qubit único usados em SparseObservable.

Essa classe é anexada a SparseObservable. Acesse-o como SparseObservable.BitTerm. Se isso for muito difícil de digitar e você estiver lidando apenas com objetos :class:¬SparseObservable` e o nome BitTerm não for ambíguo, talvez seja melhor encurtá-lo como:

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

Você pode acessar todos os valores da enumeração pelo nome completo em letras maiúsculas ou pelo rótulo de uma única letra. Os rótulos de letra única geralmente não são identificadores válidos no site Python, portanto, é necessário usar a notação de indexação para acessá-los:

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

A estrutura numérica deles é que todos são valores de quatro bits, dos quais os dois bits inferiores são a representação simpática (sem fase) do operador de Pauli relacionado ao objeto, em que o bit inferior denota uma contribuição de ZZ e o segundo inferior uma contribuição de XX, enquanto os dois bits superiores são 00 para um operador de Pauli, 01 para o projetor de estado próprio negativo e 10 para o projetor de estado próprio positivo.

Valores

X

Valor Padrão: 2

O operador Pauli XX. Usa o rótulo de letra única "X".

Plus

Valor Padrão: 10

O projetor para o estado próprio positivo do operador XX : ++\lvert+\rangle\langle+\rvert. Usa o rótulo de letra única "+".

MINUS

Valor Padrão: 6

O projetor para o estado próprio negativo do operador XX : \lvert-\rangle\langle-\rvert. Usa o rótulo de letra única "-".

Y

Valor Padrão: 3

O operador Pauli YY. Usa o rótulo de letra única "Y".

DIREITA

Valor Padrão: 11

O projetor para o estado próprio positivo do operador YY : rr\lvert r\rangle\langle r\rvert. Usa o rótulo de letra única "r".

ESQUERDA

Valor Padrão: 7

O projetor para o estado próprio negativo do operador YY : ll\lvert l\rangle\langle l\rvert. Usa o rótulo de letra única "l".

Z

Valor Padrão: 1

O operador Pauli ZZ. Usa o rótulo de letra única "Z".

ZERO

Valor Padrão: 9

O projetor para o estado próprio positivo do operador ZZ : 00\lvert0\rangle\langle0\rvert. Usa o rótulo de letra única "0".

ONE

Valor Padrão: 5

O projetor para o estado próprio negativo do operador ZZ : 11\lvert1\rangle\langle1\rvert. Usa o rótulo de letra única "1".

Atributos

label

O rótulo da cadeia de caracteres de um único caractere usado para representar esse termo no SparseObservable alfabeto.

Cada um dos atributos do tipo matriz se comporta como uma sequência Python. Você pode indexar e fatiar esses dados com a semântica padrão list-como a semântica padrão. O corte de um atributo retorna um Numpy ndarray contendo uma cópia dos dados relevantes com o dtype natural do campo; isso permite que você faça matemática facilmente nos resultados, como operações bit a bit em bit_terms. Você pode atribuir a índices ou fatias de cada um dos atributos, mas lembre-se de que é necessário manter as regras de coerência de dados ao fazer isso. Por exemplo:

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

A redução acima para as bases de Pauli também pode ser obtida com pauli_bases().

Ordenação canônica

Para qualquer observável matemático dado, há várias maneiras de representá-lo com SparseObservable. Por exemplo, o mesmo conjunto de termos de um único bit e seus índices correspondentes podem aparecer várias vezes no observável. Matematicamente, isso é equivalente a ter apenas um único termo com todos os coeficientes somados. Da mesma forma, os termos da soma em a SparseObservable podem estar em qualquer ordem e representar o mesmo observável, já que a adição é comutativa (embora a adição de ponto flutuante não seja associativa), SparseObservable não garante a ordem da soma).

Essas duas categorias de degeneração de representação podem levar o == operador a afirmar que duas observáveis não são iguais, apesar de representarem o mesmo objeto. Nesses casos, pode ser conveniente definir uma forma canônica, que permita comparar os observáveis estruturalmente.

Você pode colocar um SparseObservable na forma canônica usando o método simplify() método. A ordenação precisa dos termos na ordenação canônica não é especificada e pode mudar entre as versões do Qiskit. Na mesma versão do Qiskit, no entanto, você pode comparar dois observáveis estruturalmente, comparando suas formas simplificadas.

Nota

Se você quiser levar em conta a tolerância de ponto flutuante na comparação, é mais seguro usar uma receita como:

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

A forma canônica produzida por simplify() por si só não detectará universalmente todos os observáveis que são equivalentes devido ao alfabeto de base supercompleto. Para obter uma expressão única, você pode primeiro representar o observável usando apenas termos de Pauli, chamando as_paulis(), seguido de simplify(). Observe que a expansão do projetor (por exemplo + em I e X) não é computacionalmente viável em escala.

Indexando

SparseObservable comporta-se como uma sequência Python (a forma padrão, não a expandida collections.abc.Sequence). O observável pode ser indexado por números inteiros e iterado para gerar termos individuais.

Cada termo aparece como uma instância de uma classe autônoma. Os termos individuais são copiados do observável básico; as mutações neles não afetarão o observável.

Termo

class Term(num_qubits, coeff, bit_terms, indices)

GitHub

Bases: object

Um único termo de um SparseObservable.

Normalmente, eles são criados por meio de indexação ou iteração em um arquivo SparseObservable.

bit_labels

bit_labels()

Retorna os rótulos de bits do termo como string.

Os rótulos dos bits corresponderão à ordem de SparseTerm.indices, de modo que o i-ésimo caractere da string seja aplicado ao índice do qubit em term.indices[i].

Retorna

Os termos de bits sem identidade como uma cadeia concatenada.

bit_terms

Visualização somente de leitura dos termos individuais de um único qubit.

Os únicos valores válidos na matriz são aqueles com um BitTerm.

coeff

O coeficiente do termo.

copy

copy()

Obtenha uma cópia deste termo.

indices

Visualização somente de leitura dos índices de cada termo de qubit único sem identidade.

Os índices sempre estarão em ordem ordenada.

num_qubits

O número de qubits em que o termo é definido.

pauli_base

pauli_base()

Obtenha um Pauli objeto que representa a base de medição necessária para esse termo.

Por exemplo, o projetor 0l+ retornará um Pauli ZYX. O resultado Pauli resultante é denso, no sentido de que as identidades explícitas são armazenadas. Uma identidade na saída de Pauli não requer uma medida concreta.

Retorna: Pauli: o operador Pauli que representa o necessário

base de medição.

Veja Também

SparseObservable.pauli_bases()

Um método semelhante para um observável inteiro de uma só vez.

to_observable

to_observable()

Converta esse termo em um SparseObservable.


Construção

SparseObservable define vários construtores. O construtor padrão tentará delegar a um dos construtores mais específicos, com base no tipo de entrada. Você sempre pode usar os construtores específicos para ter mais controle sobre a construção.

Método
Resumo
from_label()Converter um rótulo de string denso em um único termo SparseObservable.
from_list()Soma uma lista de tuplas de rótulos de cadeia densa e os coeficientes associados em um observável.
from_sparse_list()Soma uma lista de tuplas de rótulos de cadeia de caracteres esparsos, os qubits aos quais eles se aplicam e seus coeficientes em um observável.
from_pauli()Elevar um único Pauli em um único termo SparseObservable.
from_sparse_pauli_op()Elevar um SparsePauliOp em um SparseObservable.
from_terms()Soma de instâncias individuais explícitas Term instâncias.
from_raw_parts()Crie o observável a partir das matrizes de dados brutos.

__new__

__new__(data, /, num_qubits=None)

O construtor padrão do SparseObservable.

Isso delega a um dos métodos de construtor de conversão explícitos, com base no tipo do argumento data . Se num_qubits for fornecido e o construtor implícito pelo tipo de data não aceitar um número, o número inteiro fornecido deverá corresponder à entrada.

Parâmetros

  • data - O tipo de dados da entrada. Isso pode ser outro SparseObservablee, nesse caso, a entrada é copiada, um Pauli ou SparsePauliOp, caso em que from_pauli() ou from_sparse_pauli_op() são chamados conforme apropriado, ou pode ser uma lista em um formato válido para from_list() ou from_sparse_list().
  • num_qubits (int|None) – Número opcional de qubits para o operador. Para a maioria das entradas de dados, isso pode ser inferido e não precisa ser passado. Isso só é necessário para listas vazias ou para o formato de lista esparsa. Se for fornecido desnecessariamente, deverá corresponder à entrada de dados.

Além dos construtores baseados em conversão, há também métodos auxiliares que constroem formas especiais de observáveis.

Método
Resumo
zero()O operador zero em um determinado número de qubits.
identity()O operador de identidade em um determinado número de qubits.

Conversões

Um arquivo existente SparseObservable existente pode ser convertido em outros operadores quantum_info operadores ou formatos genéricos. Observe que outros objetos podem não ser capazes de representar o mesmo observável de forma tão eficiente quanto SparseObservableincluindo a necessidade potencial de uma memória exponencialmente maior.

Método
Resumo
as_paulis()Crie um novo SparseObservableexpandindo apenas em termos de operadores Pauli.
to_sparse_list()Expresse o observável em um formato de lista esparsa com elementos (bit_terms, indices, coeff).

Além disso, SparsePauliOp.from_sparse_observable() está disponível para conversão dessa classe para SparsePauliOp. Esteja ciente de que esse método sofre das mesmas preocupações de uso de memória exponencial que o as_paulis().


Manipulação matemática

SparseObservable suporta o conjunto padrão de operadores matemáticos do Python, como outros quantum_info operadores.

Na aritmética básica, você pode:

  • adicionar dois observáveis usando +
  • subtrair dois observáveis usando -
  • multiplicar ou dividir por um int, float ou complex usando * e /
  • negar todos os coeficientes em um observável com um unário -

Cada um dos operadores aritméticos binários básicos tem um método in-place especializado correspondente, que altera o lado esquerdo in-place. O uso desses operadores é normalmente mais eficiente do que o dos operadores infixos, especialmente para criar um observável em um loop.

O produto tensorial é calculado com tensor() (para a ordem padrão de justaposição dos rótulos de Pauli) ou expand() (para a ordem inversa). O operador ^ é sobrecarregado para ser equivalente a tensor().

Nota

Ao usar os operadores binários ^ (tensor()) e & (compose()), lembre-se de que as regras de precedência de operador do Python podem fazer com que a ordem de avaliação seja diferente da sua expectativa. Em particular, o operador + se vincula mais firmemente do que ^ ou &, assim como * se vincula mais firmemente do que +.

Ao usar os operadores em expressões mistas, é mais seguro usar parênteses para agrupar os operandos dos produtos tensoriais.

A SparseObservable tem uma forma bem definida de adjoint(). As noções de conjugação complexa escalar (conjugate()) e transposição de valor real (transpose()) são definidas de forma análoga à representação matricial de outros operadores Pauli no Qiskit.

Notas sobre eficiência

Internamente, SparseObservable é mutável no local, incluindo o uso de vetores expansíveis com alocação excessiva para estender o número de termos. Isso significa que o custo de anexar a um observável usando += é amortizado linearmente no número total de termos adicionados, em vez da complexidade quadrática que o + binário exigiria.

As adições e subtrações são implementadas por uma operação de empilhamento de termos; não há "simplificação" automática (soma de termos semelhantes), porque a maioria das adições para construir um observável gera apenas um pequeno número de duplicações, e a detecção de termos semelhantes tem custos adicionais. Se isso não se adequar aos seus casos de uso, você pode chamar periodicamente simplify()ou discutir outras APIs conosco para melhorar a criação de observáveis.


Atributos

bit_terms

Uma lista simples de termos de um único qubit. Isso é mais naturalmente uma lista de listas, mas é armazenada de forma plana por motivos de uso de memória e localidade, com as sublistas denotadas por limites.

boundaries

Índices que dividem bit_terms e indices em sublistas para cada termo individual na soma. boundaries[0] : boundaries[1] é o intervalo de índices em bit_terms e indices que correspondem ao primeiro termo da soma. Todos os índices de qubit não especificados são implicitamente a identidade. Esse é um item a mais do que coeffsjá que boundaries[0] é sempre um zero explícito (para facilitar o algoritmo).

coeffs

Os coeficientes de cada termo abstrato na soma. Isso tem tantos elementos quanto termos na soma.

indices

Uma lista simples dos índices de qubit que as entradas correspondentes em bit_terms atuam. Essa lista deve ser sempre classificada por termo, em que um termo é uma sublista, conforme indicado por boundaries.

Aviso

Se estiver escrevendo nesse atributo a partir do espaço Python, você deve garantir que só escreva em índices que estejam ordenados por termo.

num_qubits

O número de qubits em que o operador atua.

Isso não pode ser inferido de nenhuma outra forma ou valor, pois as identidades não são armazenadas explicitamente.

num_terms

O número de termos na soma que esse operador está rastreando.


Métodos

adjoint

adjoint()

Calcule o adjunto desse observável.

Isso é bem definido no sentido matemático abstrato. Todos os termos do alfabeto de um único qubit são autoadjuntos, portanto, o resultado dessa operação é o mesmo observável, exceto que seus coeficientes são todos conjugados complexos.

Exemplos

>>> 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 um layout de transpilador a isso SparseObservable.

Normalmente, você terá definido seu observável em termos dos qubits virtuais dos circuitos que usará para preparar os estados. Após a transpilação, os qubits virtuais são mapeados para qubits físicos específicos em um dispositivo, que pode ser maior do que o seu circuito. Esse mapeamento também pode mudar no decorrer do circuito. Esse método transforma o observável de entrada em qubits virtuais em um observável que é adequado para ser aplicado imediatamente após o circuito físico totalmente transpilado.

Parâmetros

  • layout (TranspileLayout |list[int] | None) – O layout a ser aplicado. A maioria dos usos dessa função deve passar o campo QuantumCircuit.layout de um circuito que foi transpilado para hardware. Além disso, você pode passar uma lista de novos índices de qubit. Se for fornecido explicitamente como None, nenhum remapeamento será aplicado (mas você ainda poderá usar num_qubits para expandir o observável).
  • num_qubits (int | None) – O número de qubits para expandir o observável. Se não for fornecido, a saída terá a mesma largura da entrada fornecida TranspileLayoutou a mesma largura da entrada se o endereço layout for fornecido em outro formato.

Retorna

Um novo SparseObservable com o layout fornecido aplicado.

as_paulis

as_paulis()

Expresse o observável somente em termos de Pauli, escrevendo cada projetor como uma soma de termos de Pauli.

Observe que não há garantia da ordem dos termos de Pauli resultantes. Use SparseObservable.simplify() além disso, para obter uma representação canônica.

Aviso

Observe que isso usará pelo menos 2n2^n termos se houver nn projetores de um único qubit presentes, o que pode levar a um número exponencial de termos.

Retorna

O mesmo observável, mas expresso apenas em termos de Pauli.

Exemplos

Reescreva um observável em termos de projetores em operadores 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 pequenos, isso pode ser usado com simplify() como uma 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()
Veja Também

SparsePauliOp.from_sparse_observable()

Um construtor de SparsePauliOp que pode converter um SparseObservable na SparsePauliOp representação densa de Pauli.

clear

clear()

Limpe todos os termos desse operador, tornando-o igual ao operador zero novamente.

Isso não altera a capacidade das alocações internas; portanto, operações posteriores de adição ou subtração podem não exigir uma realocação.

Exemplos

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

Verifique se o observável comuta com outro.

Parâmetros

  • other (SparseObservable) – O outro observável para verificar a comutação.
  • tol (float) – Se os coeficientes no produto de si mesmo e do outro estiverem abaixo da tolerância (em magnitude), os termos são ignorados.

Retorna

True se os termos se compensarem, até a tolerância, False caso contrário.

Aumentos

TypeError – Se não other pudesse ser coagido a SparseObservable.

compose

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

Componha outro SparseObservable sobre este.

Em termos de álgebras de operadores, a composição corresponde à multiplicação à esquerda: c = a.compose(b) corresponde a $C = B A$. Em outras palavras, a.compose(b) retorna um operador que "executa a e, em seguida, executa b no resultado". Em vez disso, o argumento front=True torna essa multiplicação correta.

self e other devem ter o mesmo tamanho, a menos que qargs seja fornecido, caso em que other pode ser menor que self, desde que o número de qubits em other e o comprimento de qargs sejam iguais. qargs nunca pode conter duplicatas ou índices de qubits que não existam em self.

Observe que essa função pode causar uma explosão exponencial do uso de memória do observável, pois o alfabeto de SparseObservable não é fechado sob composição; a composição de dois termos de bit único pode ser uma soma, que multiplica o número total de termos. Esse uso de memória não é _necessariamente_ inerente ao observável resultante, mas encontrar uma refatoração eficiente da soma geralmente é igualmente difícil do ponto de vista computacional. É melhor usar o conhecimento do domínio de seus observáveis para minimizar o número de termos que existem, em vez de tentar simplificá-los após o fato.

Parâmetros

  • outro - o observável usado para multiplicar à esquerda self.

  • qargs -

    se fornecido, os qubits em self a serem associados aos qubits em other. Em outras palavras: se isso for dado, é semelhante a uma implementação mais eficiente de:

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

    pois nenhum observável temporário é criado para armazenar a forma de layout aplicado de other.

  • front - se True, então multiplicar à direita por other em vez de multiplicar à esquerda (padrão False). O qargs ainda é aplicado ao other. Isso é mais útil quando qargs está definido, ou other pode ser um objeto que deve ser coagido a SparseObservable.

conjugate

conjugate()

Calcule a conjugação complexa desse observável.

Essa operação é definida em termos das convenções de matriz padrão do Qiskit, em que a forma da matriz é considerada na base computacional $Z$. Os termos do alfabeto relacionados a $X$- e $Z$ não são afetados pela conjugação complexa, mas os termos relacionados a $Y$ modificam seus termos do alfabeto. Exatamente:

  • YY conjugue com Y-Y
  • rr\lvert r\rangle\langle r\rvert conjugados para ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert conjugados para rr\lvert r\rangle\langle r\rvert

Além disso, todos os coeficientes são conjugados.

Exemplos

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

copy

copy()

Obtenha uma cópia desse observável.

Exemplos

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

Desenvolva essa observável por meio de um termo de Pauli.

Uma evolução da observável OO por um PP de Pauli corresponde a POPP^\dagger O P.

Ao contrário de uma implementação literal por meio de duas composições completas, este método realiza a conjugação diretamente no nível de um único qubit, utilizando uma tabela de consulta fixa. Isso evita a materialização de quaisquer termos intermediários SparseObservable e calcula a observável evoluída em uma única passagem pelos termos. self e other deve ter o mesmo número de qubits, a menos que qargs seja especificado; nesse caso, other pode ser menor que self, desde que o número de qubits em other e o comprimento de qargs sejam iguais. qargs especifica quais qubits de self são evoluídos por other.

Atualmente, esse método suporta a evolução apenas por meio de um operador de termo único, o que significa que other deve ser um operador de Pauli representado por Pauli.

Parâmetros

  • outro – o operador de Pauli, usado para conjugar self.
  • qargs – se fornecido, os qubits em self a serem evoluídos por other. O comprimento deve corresponder ao número de qubits em other.

Retorna

Uma nova forma evoluiu SparseObservable com as conjugações aplicadas.

Aumentos

  • TypeError – se não other for do tipo Pauli.
  • ValueError – se self e other tiverem números diferentes de qubits (e não qargs for especificado).
  • ValueError – se qargs o comprimento não corresponder other ao número de qubits.
  • ValueError – se qargs contiver duplicatas ou índices fora do intervalo.
  • ValueError – se other contiver mais de um termo.

expand

expand(other, /)

Produto tensor de ordem inversa.

Isso é equivalente a other.tensor(self), exceto pelo fato de que other será primeiro convertido para SparseObservable se ainda não for um (chamando o construtor padrão).

Parâmetros

outro - o observável a ser colocado no lado esquerdo do produto tensorial.

Exemplos

Isso é equivalente a tensor() com a ordem dos argumentos invertida:

>>> left = SparseObservable.from_label("XYZ")
>>> right = SparseObservable.from_label("+-IIrl")
>>> assert left.tensor(right) == right.expand(left)
Veja Também

tensor()

A mesma função com a ordem dos argumentos invertida. tensor() é a ordenação de argumentos mais padrão e corresponde às outras convenções do Qiskit.

from_label

static from_label(label, /)

Construa um observável de termo único a partir de um rótulo de cadeia densa.

O operador resultante terá um coeficiente de 1. O rótulo deve ser uma sequência do alfabeto 'IXYZ+-rl01'. O rótulo é interpretado de forma análoga a uma cadeia de bits. Em outras palavras, a letra mais à direita está associada ao qubit 0, e assim por diante. Isso é o mesmo que os rótulos de Pauli e SparsePauliOp.

Parâmetros

label (str) – o rótulo denso.

Exemplos

>>> 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)
Veja Também

from_list()

Uma generalização desse método que constrói um operador de soma a partir de vários rótulos e seus coeficientes correspondentes.

from_list

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

Construa um observável a partir de uma lista de rótulos e coeficientes densos.

Isso é análogo ao SparsePauliOp.from_list()exceto que ele usa o alfabeto estendido de SparseObservable. Nesse formulário denso, você deve fornecer todas as identidades explicitamente em cada rótulo.

O rótulo deve ser uma sequência do alfabeto 'IXYZ+-rl01'. O rótulo é interpretado de forma análoga a uma cadeia de bits. Em outras palavras, a letra mais à direita está associada ao qubit 0, e assim por diante. Isso é o mesmo que os rótulos de Pauli e SparsePauliOp.

Parâmetros

  • iter (list[tuple[str, complex]]) – Pares de rótulos e seus coeficientes associados a serem somados. Os rótulos são interpretados da mesma forma que em from_label().
  • num_qubits (int | None) – Não é necessário especificar isso se você tiver certeza de que iter não é uma sequência vazia, pois isso pode ser inferido a partir dos comprimentos dos rótulos. Se o iter puder estar vazio, você deverá especificar esse argumento para não ambiguidade de quantos qubits o observável representa. Se isso for fornecido e iter não estiver vazio, o valor deverá corresponder aos comprimentos do rótulo.

Exemplos

Construa um observável a partir de uma lista de rótulos do mesmo tamanho:

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

Use num_qubits para eliminar a ambiguidade de entradas potencialmente vazias:

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

Esse método é equivalente a chamadas para from_sparse_list() com o campo explícito qubit-arguments definido como números inteiros decrescentes:

>>> 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
Veja Também

from_label()

Um construtor semelhante, mas que recebe apenas um único rótulo e sempre tem seu coeficiente definido como 1.0.

from_sparse_list()

Construa o observável a partir de uma lista de rótulos sem identidades explícitas, mas com os qubits aos quais cada termo de qubit único se aplica listado explicitamente.

from_pauli

static from_pauli(pauli, /)

Construir um SparseObservable a partir de uma única Pauli instância.

O observável de saída terá um único termo, com um coeficiente unitário dependente da fase.

Parâmetros

pauli (Pauli) – a única Pauli para converter.

Exemplos

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

Construa um SparseObservable a partir de matrizes Numpy brutas que correspondem à representação de dados necessária descrita na documentação em nível de classe.

Os dados de cada matriz são copiados em alocações de espaço Rust novas e crescentes.

Parâmetros

  • num_qubits - número de qubits no observável.

  • coeffs - coeficientes complexos de cada termo do observável. Esse deve ser um array Numpy com dtype complex128.

  • bit_terms - lista achatada dos termos de um único qubit que inclui todos os termos completos. Esse deve ser um array Numpy com dtype uint8 (que é compatível com BitTerm).

  • índices - lista ordenada por termos achatados dos qubits aos quais cada termo de qubit único corresponde. Esse deve ser um array Numpy com dtype uint32.

  • limites - os índices que dividem bit_terms e indices em termos. Esse deve ser um array Numpy com dtype uintp.

  • verificação -

    se True (o padrão), validar se os dados satisfazem todas as garantias de coerência. Se False, nenhuma verificação é feita.

    Aviso

    Se check=False, os bit_terms devem ser absolutamente todos valores válidos de SparseObservable.BitTerm. Se não forem, poderá ocorrer um comportamento indefinido no espaço Rust, invalidando totalmente a execução do programa.

Exemplos

Construa uma soma de ZZ em 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)

Construa um observável a partir de uma lista de rótulos, os qubits aos quais cada item se aplica e o coeficiente de todo o termo.

Isso é análogo ao SparsePauliOp.from_sparse_list()exceto que ele usa o alfabeto estendido de SparseObservable.

Os campos "labels" (rótulos) e "indices" (índices) das triplas são associados por meio de um zíper. Por exemplo, isso significa que uma chamada para from_list() pode ser convertida para a forma usada por esse método, definindo o campo "indices" de cada tripla como (num_qubits-1, ..., 1, 0).

Parâmetros

  • iter (list[tuple[str, Sequence[int], complex]]) – triplas de rótulos, os qubits aos quais cada termo de qubit único se aplica e o coeficiente de todo o termo.
  • num_qubits (int) – o número de qubits no operador.

Exemplos

Construa um operador simples:

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

Construa o observável de identidade (embora, na verdade, basta usar identity()):

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

Esse método pode replicar o comportamento de from_list()se o campo qubit-arguments da tripla for definido como números inteiros decrescentes:

>>> 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
Veja Também

to_sparse_list()

O inverso desse método.

from_sparse_pauli_op

static from_sparse_pauli_op(op, /)

Construir um SparseObservable a partir de uma SparsePauliOp instância.

Essa será uma tradução direta da versão SparsePauliOpem particular, não há soma imediata de termos semelhantes, nem qualquer tentativa de refatorar as somas de termos de Pauli em operadores de projeção equivalentes.

Parâmetros

op (SparsePauliOp) – o operador a ser convertido.

Exemplos

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

Construa um SparseObservable a partir de termos individuais.

Todos os termos devem ter o mesmo número de qubits. Se fornecido, o argumento num_qubits deve corresponder aos termos.

Nenhuma simplificação é feita como parte da criação observável.

Parâmetros

  • obj (Iterable[Term]) – Iterável de termos individuais para construir o observável.
  • num_qubits (int | None) – O número de qubits em que o observável deve atuar. Isso geralmente é inferido a partir da entrada, mas pode ser explicitamente fornecido para lidar com o caso de um iterável vazio.

Retorna

O observável correspondente.

identity

static identity(num_qubits)

Obtém o operador de identidade sobre o número determinado de qubits.

Exemplos

Obtenha o operador de identidade para 100 qubits:

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

pauli_bases

pauli_bases()

Obter um PauliList que representa a base de medição necessária para cada termo (em ordem) nesse observável.

Por exemplo, o projetor 0l+ retornará um Pauli ZXY. O resultado Pauli resultante é denso, no sentido de que as identidades explícitas são armazenadas. Uma identidade na saída de Pauli não requer uma medida concreta.

Isso retornará uma entrada na lista de Pauli para cada termo na soma.

Retorna

a lista de operadores Pauli que representa as bases de medição necessárias.

Tipo de retorno

PauliList

simplify

simplify(tol=1e-08)

Some todos os termos semelhantes nesse operador, removendo-os se o coeficiente complexo resultante tiver um valor absoluto dentro da tolerância de zero.

Como efeito colateral, isso classifica o operador em ordem canônica.

Nota

Ao utilizar isso para comparações de igualdade, observe que o arredondamento de números de ponto flutuante e a não associatividade da adição de números de ponto flutuante podem fazer com que coeficientes diferentes de zero dos termos somados sejam considerados desiguais. Para comparar duas grandezas observáveis dentro de um limite de tolerância, o método mais seguro é comparar a diferença canonicizada entre as duas grandezas observáveis com o valor zero.

Parâmetros

tol (float) – depois de somar termos semelhantes, todos os coeficientes cujo valor absoluto for menor do que a tolerância absoluta fornecida serão suprimidos da saída.

Exemplos

Usando simplify() para comparar dois operadores que representam o mesmo observável, mas que seriam comparados de forma desigual devido aos testes estruturais por padrão:

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

Observe que, no exemplo acima, os coeficientes são escolhidos de forma que todos os cálculos de ponto flutuante sejam exatos e não haja problemas intermediários de arredondamento ou associatividade. Se não for possível garantir que esse seja o caso, a forma mais segura é:

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

Produto tensorial de dois observáveis.

A ordenação de bits é definida de forma que os índices de qubit do argumento permaneçam os mesmos e os índices de self sejam deslocados pelo número de qubits em other. Essa é a mesma convenção usada pelo restante dos operadores do Qiskit quantum_info operadores.

Essa função é usada para o operador infixo ^ . Se estiver usando esse operador, esteja ciente de que as regras de precedência de operador do Python podem fazer com que a ordem de avaliação seja diferente da sua expectativa. Em particular, o operador + se vincula mais firmemente do que ^, assim como * se vincula mais firmemente do que +. Use parênteses para corrigir a ordem de avaliação, se necessário.

O argumento será convertido para SparseObservable usando seu construtor padrão, se ainda não estiver no formato correto.

Parâmetros

outro - o observável a ser colocado no lado direito do produto tensorial.

Exemplos

A ordem dos bits é tal que o produto tensorial de dois observáveis feitos a partir de um único rótulo "se parece" com um observável feito pela concatenação das duas cadeias:

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

Você também pode usar o operador infixo ^ para produtos tensoriais, que converterá de forma semelhante o lado direito da operação se ele ainda não for um SparseObservable:

>>> assert SparseObservable("rl") ^ Pauli("XYZ") == SparseObservable("rlXYZ")
Veja Também

expand()

A mesma função, mas com a ordem dos argumentos invertida. Isso pode ser útil se você gostar de usar o comportamento de conversão para o argumento, mas quiser que seu SparseObservable existente esteja no lado direito da ordenação do tensor.

to_sparse_list

to_sparse_list()

Expresse o observável em termos de um formato de lista esparsa.

Isso pode ser visto como uma contraoperação de SparseObservable.from_sparse_list()no entanto, não é garantido que a ordem dos termos seja a mesma depois de uma viagem de ida e volta para uma lista esparsa.

Exemplos

>>> obs = SparseObservable.from_list([("IIXIZ", 2j), ("IIZIX", 2j)])
>>> reconstructed = SparseObservable.from_sparse_list(obs.to_sparse_list(), obs.num_qubits)
Veja Também

from_sparse_list()

O construtor que pode interpretar essas listas.

transpose

transpose()

Calcule a transposição da matriz desse observável.

Essa operação é definida em termos das convenções de matriz padrão do Qiskit, em que a forma da matriz é considerada na base computacional $Z$. Os termos do alfabeto relacionados a $X$- e $Z$ não são afetados pela transposição, mas os termos relacionados a $Y$ modificam seus termos do alfabeto. Exatamente:

  • YY transpõe para Y-Y
  • rr\lvert r\rangle\langle r\rvert transpõe para ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert transpõe para rr\lvert r\rangle\langle r\rvert

Exemplos

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

zero

static zero(num_qubits)

Obtém o operador zero sobre o número dado de qubits.

O operador zero é o operador cujo valor de expectativa é zero para todos os estados quânticos. Ele não tem termos. É o elemento de identidade para a adição de duas instâncias SparseObservable qualquer coisa adicionada ao operador zero é igual a ele mesmo.

Se você quiser que o projetor fique no estado de todos os zeros, use:

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

Exemplos

Obtenha o operador zero para 100 qubits:

>>> SparseObservable.zero(100)
<SparseObservable with 0 terms on 100 qubits: 0.0>
Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.