Expressões clássicas
qiskit.circuit.classical
Esse módulo contém uma representação exploratória de operações em tempo real sobre valores clássicos durante a execução do circuito.
Atualmente, apenas expressões simples em bits e registros que resultam em um valor booleano são suportadas, e elas são válidas apenas para uso nas condições de QuantumCircuit.if_test() (IfElseOp) e QuantumCircuit.while_loop() (WhileLoopOp), e no destino de QuantumCircuit.switch() (SwitchCaseOp).
Este é um módulo exploratório e, embora nos comprometamos com a política padrão de depreciação do Qiskit, esteja ciente de que o módulo terá um escopo deliberadamente limitado no início, e as primeiras versões podem não evoluir de forma limpa para a versão final. É possível que vários componentes desse módulo sejam substituídos (sujeitos a depreciações) em vez de aprimorados em um novo formato.
O sistema de tipos e a árvore de expressões serão expandidos com o tempo, e é possível que os tipos permitidos de algumas operações precisem mudar entre as versões do Qiskit à medida que os recursos de processamento clássico se desenvolvem.
Expressões
qiskit.circuit.classical.expr
Os componentes necessários para criar expressões são todos exportados do namespace expr dentro de qiskit.circuit.classicalportanto, você pode escolher se deseja usar o acesso qualificado (por exemplo expr.Value) ou importar os nomes de que você precisa diretamente e chamá-los sem o prefixo.
Há dois caminhos para a construção de expressões. As classes que formam a representação do sistema de expressão têm construtores que realizam verificação de tipo zero; cabe ao chamador garantir que eles estejam construindo objetos válidos. Para uma interface mais amigável para a construção direta, há funções auxiliares associadas à maioria das classes que fazem validação e inferência de tipos. Eles são descritos abaixo, em Construção.
Representação
O sistema de expressão é baseado na representação em árvore. Todos os nós da árvore são instâncias finais (não herdáveis) da classe base abstrata:
Expr
class qiskit.circuit.classical.expr.Expr
Bases: object
Classe base da raiz de todos os nós na árvore de expressão. O caso base nunca deve ser instanciado diretamente.
Isso não deve ser subclassificado pelos usuários; as subclasses formam os dados internos da representação das expressões, e não faz sentido adicionar mais fora do código da biblioteca do Qiskit.
Todas as subclasses são responsáveis por definir seu type atributo em seu __init__, e não devem chamar o inicializador da classe pai.
Esses objetos são mutáveis e não devem ser reutilizados em um local diferente sem uma cópia.
Todas as instâncias Expr definem um atributo booleano const , que indica se a expressão pode ser avaliada em tempo de compilação. A maioria das classes de expressão inferem isso durante a construção com base na constância de seus operandos.
A base para variáveis dinâmicas é a variável Varque pode ser uma variável de tempo real arbitrariamente digitada ou um invólucro em torno de uma variável Clbit ou ClassicalRegister.
Var
class qiskit.circuit.classical.expr.Var(var, type, *, name=None)
Bases: Expr
Uma variável clássica.
Essas variáveis assumem duas formas: uma variável de novo estilo que possui seu local de armazenamento e tem um nome associado; e uma variável de estilo antigo que envolve um Clbit ou ClassicalRegister que é propriedade de algum circuito que a contém. Em geral, a construção de variáveis para uso em programas deve usar Var.new() ou QuantumCircuit.add_var().
As variáveis são imutáveis após a criação, portanto, podem ser usadas como chaves de dicionário.
name
O nome da variável. Isso deve existir se o atributo backing var for um UUID,, ou seja, se for uma variável do novo estilo, e deve ser None `` se for uma variável do estilo antigo.
new
classmethod new(name, ty)
Gera uma nova variável nomeada que possui seu próprio armazenamento de apoio.
var
Uma referência ao armazenamento de dados de backup da Var instância. Ao migrar instâncias do Clbit tipo antigo ClassicalRegister para um Var, isso é exatamente o Clbit ou ClassicalRegister. Se a variável for uma variável clássica do novo estilo (aquela que possui seu próprio espaço de armazenamento, separado do antigo Clbit/ClassicalRegister modelo), este campo será um UUID para identificá-la de forma exclusiva.
Da mesma forma, os literais usados em expressões (como números inteiros) devem ser elevados a nós Value com tipos associados. A Value é sempre considerada uma expressão constante.
Valor
As variáveis de alongamento para uso em expressões de duração são representadas pelo nó Stretch nó.
Esticar
class qiskit.circuit.classical.expr.Stretch(var, name)
Bases: Expr
Uma variável de extensão.
Em geral, a construção de variáveis de extensão para uso em programas deve usar Stretch.new() ou QuantumCircuit.add_stretch()
name
O nome da variável de extensão.
new
classmethod new(name)
Gerar uma nova variável de extensão nomeada.
var
A UUID para identificar exclusivamente esse trecho.
As operações tradicionalmente associadas aos operadores pré, pós ou infixos na programação são representadas pelos operadores Unary e Binary conforme apropriado. Cada uma delas recebe um código de tipo de operação, que é exposto como enumerações dentro de cada classe como Unary.Op e Binary.Op respectivamente.
Unário
class qiskit.circuit.classical.expr.Unary(op, operand, type)
Bases: Expr
Uma expressão unária.
Parâmetros
- op - O código de operação que descreve a operação que está sendo realizada.
- operando - O operando da operação.
- type - O tipo resolvido do resultado.
Op
class Op(*values)
Bases: Enum
Enumeração dos códigos de operação para operações unárias.
A negação bit a bit BIT_NOT usa um único bit ou um número inteiro sem sinal de largura conhecida e retorna um valor do mesmo tipo.
A negação lógica LOGIC_NOT recebe uma entrada que é implicitamente coagida a um booleano e retorna um booleano.
A negação aritmética NEGATE recebe como entrada um valor do tipo float ou duration e retorna um valor do mesmo tipo.
Binário
class qiskit.circuit.classical.expr.Binary(op, left, right, type)
Bases: Expr
Uma expressão binária.
Parâmetros
- op - O código de operação que descreve a operação que está sendo realizada.
- left - O operando do lado esquerdo.
- right - O operando do lado direito.
- type - O tipo resolvido do resultado.
Op
class Op(*values)
Bases: Enum
Enumeração dos códigos de operação para operações binárias.
As operações bit a bit BIT_AND, BIT_OR e BIT_XOR aplicam-se a dois operandos do mesmo tipo, que deve ser um bit único ou um inteiro sem sinal de largura fixa. O tipo resultante é o mesmo que os dois tipos de entrada.
As operações lógicas LOGIC_AND e LOGIC_OR primeiro coerem implicitamente seus argumentos para booleanos e, em seguida, aplicam a operação lógica. O tipo resultante é sempre booleano.
As relações matemáticas binárias EQUAL, NOT_EQUAL, LESS, LESS_EQUAL, GREATER e GREATER_EQUAL recebem números inteiros sem sinal (com uma conversão implícita para torná-los da mesma largura) e retornam um booleano.
As operações de bitshift SHIFT_LEFT e SHIFT_RIGHT podem receber tipos de contêineres do tipo bit (por exemplo, números inteiros sem sinal) como operando à esquerda e qualquer tipo de número inteiro como operando à direita. Em todos os casos, a largura do bit de saída é a mesma da entrada, e os zeros preenchem os espaços "expostos".
Os operadores aritméticos ADD binários, SUB, MUL, e DIV podem ser aplicados a dois números de precisão flutuante ou a dois inteiros sem sinal, os quais devem ser ajustados para terem a mesma largura durante a construção por meio de uma conversão de tipo. Os DIV operadores ADD, SUB, e podem ser aplicados a duas durações, resultando em outra duração ou em um número real no caso de DIV. O MUL operador também pode ser aplicado a uma duração e a um tipo numérico, resultando em outra duração. Por fim, o DIV operador pode ser usado para dividir uma duração por um valor numérico, resultando em uma duração.
Os tipos do tipo bit (inteiros sem sinal) podem ser indexados por tipos inteiros, representados por Index. O resultado é um único bit. A expressão resultante tem um local de memória associado (e, portanto, pode ser usada como um valor l para Storeetc.) se o destino também for um valor l.
Índice
class qiskit.circuit.classical.expr.Index(target, index, type)
Bases: Expr
Uma expressão de indexação.
Parâmetros
- alvo - O objeto que está sendo indexado.
- index - A expressão que faz a indexação.
- type - O tipo resolvido do resultado.
Ao construir expressões, é preciso garantir que os tipos sejam válidos para a operação. As tentativas de construir expressões com tipos inválidos gerarão uma mensagem regular Python TypeError.
As expressões nesse sistema são definidas para atuar somente em determinados conjuntos de tipos. Entretanto, os valores podem ser convertidos em um supertipo adequado para atender aos requisitos de tipagem. Nesses casos, um nó na árvore de expressão é usado para representar a promoção. Em todos os casos em que as operações observam que "convertem implicitamente" ou "coagem" seus argumentos, a árvore de expressões deve ter esse nó representando a conversão.
Converter
class qiskit.circuit.classical.expr.Cast(operand, type, implicit=False)
Bases: Expr
Uma conversão de um tipo para outro, implícita no uso de uma expressão em um contexto diferente.
Construção
A construção direta da representação da árvore é verbosa e é fácil cometer um erro de digitação. Em muitos casos, grande parte da tipagem pode ser inferida, os valores escalares podem ser promovidos automaticamente para Value instâncias, e todas as promoções necessárias podem ser resolvidas em nós Cast adequados.
As funções e os métodos descritos nesta seção são uma maneira mais amigável de criar a árvore de expressões, mantendo-se próximos da representação interna. Todas essas funções elevarão automaticamente os valores escalares válidos do Python para o correspondente Var ou Value correspondentes e resolverão quaisquer conversões implícitas necessárias em seu nome. Se você quiser usar diretamente algum valor escalar como um nó Expr nó, você pode manualmente lift() manualmente.
lift
qiskit.circuit.classical.expr.lift(value, /, type=None)
Eleve o endereço Python value para um Value ou Var.
Se for fornecido um type explícito, a digitação na saída refletirá isso.
Exemplos
Elevação de objetos de circuito simples para serem Var instâncias:
>>> from qiskit.circuit import Clbit, ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.lift(Clbit())
Var(<clbit>, Bool())
>>> expr.lift(ClassicalRegister(3, "c"))
Var(ClassicalRegister(3, "c"), Uint(3))O tipo do valor de retorno pode ser alterado, caso o valor fornecido possa ser interpretado sem perda de informação como o tipo especificado (use cast() para realizar um conjunto completo de operações de conversão, incluindo aquelas com perda de informação):
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr, types
>>> expr.lift(ClassicalRegister(3, "c"), types.Uint(5))
Var(ClassicalRegister(3, "c"), Uint(5))
>>> expr.lift(5, types.Uint(4))
Value(5, Uint(4))Parâmetros
Tipo de retorno
Normalmente, você deve criar instâncias que possuem memória Var usando o método QuantumCircuit.add_var() para declará-las em algum contexto de circuito, já que o método QuantumCircuit não aceitará um Expr que contenha variáveis que ainda não tenham sido declaradas nele, pois ele precisa saber como alocar o armazenamento e como a variável será inicializada. No entanto, se quiser fazer isso manualmente, você deve usar a chamada de baixo nível Var.new() de baixo nível para gerar com segurança uma variável nomeada para uso.
Você pode especificar manualmente as conversões nos casos em que a conversão é permitida na forma explícita, mas pode ter perdas (como a conversão de uma precisão maior Uint para um de menor precisão).
cast
qiskit.circuit.classical.expr.cast(operand, type, /)
Cria uma conversão explícita do valor fornecido para o tipo fornecido.
Exemplos
Adicione um nó de conversão explícito que converte explicitamente um tipo de precisão maior em um de precisão menor:
>>> from qiskit.circuit.classical import expr, types
>>> value = expr.value(5, types.Uint(32))
>>> expr.cast(value, types.Uint(8))
Cast(Value(5, types.Uint(32)), types.Uint(8), implicit=False)Parâmetros
Tipo de retorno
Há funções de construtor auxiliar para cada uma das operações unárias.
bit_not
qiskit.circuit.classical.expr.bit_not(operand, /)
Cria um nó de expressão bit a bit 'not' a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando o valor em um nó Value se necessário.
Exemplos
Negação bit a bit de a ClassicalRegister:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_not(ClassicalRegister(3, "c"))
Unary(Unary.Op.BIT_NOT, Var(ClassicalRegister(3, 'c'), Uint(3)), Uint(3))Parâmetros
operand (Any)
Tipo de retorno
logic_not
qiskit.circuit.classical.expr.logic_not(operand, /)
Cria um nó de expressão "não" lógico a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando o valor para um nó Value se necessário.
Exemplos
Negação lógica de a ClassicalRegister:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.logic_not(ClassicalRegister(3, "c"))
Unary(Unary.Op.LOGIC_NOT, Cast(Var(ClassicalRegister(3, 'c'), Uint(3)), Bool(), implicit=True), Bool())Parâmetros
operand (Any)
Tipo de retorno
negate
qiskit.circuit.classical.expr.negate(operand, /)
Negar um nó de expressão a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando o valor a um Value nó, se necessário.
Exemplos
Negação de um número de ponto flutuante:
>>> from qiskit.circuit.classical import expr
>>> expr.negate(5.0)
Unary(Unary.Op.NEGATE, Value(5.0, Float()), Float())Negação de uma duração:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.negate(Duration.dt(1000))
Unary(Unary.Op.NEGATE, Value(Duration.dt(1000), Duration()), Duration())Parâmetros
operand (Any)
Tipo de retorno
Da mesma forma, as operações e relações binárias têm funções auxiliares definidas.
bit_and
qiskit.circuit.classical.expr.bit_and(left, right, /)
Cria um nó de expressão bit a bit 'and' a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores em nós Value se necessário.
Exemplos
"e" bit a bit de um registro clássico e um literal de número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_and(ClassicalRegister(3, "c"), 0b111)
Binary(Binary.Op.BIT_AND, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(7, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
bit_or
qiskit.circuit.classical.expr.bit_or(left, right, /)
Cria um nó de expressão "ou" bit a bit a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores em nós Value se necessário.
Exemplos
"Ou" bit a bit de um registro clássico e um literal de número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_or(ClassicalRegister(3, "c"), 0b101)
Binary(Binary.Op.BIT_OR, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(5, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
bit_xor
qiskit.circuit.classical.expr.bit_xor(left, right, /)
Cria um nó de expressão bit a bit "exclusivo ou" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores em nós Value se necessário.
Exemplos
"Ou exclusivo" bit a bit de um registro clássico e um literal inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.bit_xor(ClassicalRegister(3, "c"), 0b101)
Binary(Binary.Op.BIT_XOR, Var(ClassicalRegister(3, 'c'), Uint(3)), Value(5, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
logic_and
qiskit.circuit.classical.expr.logic_and(left, right, /)
Cria um nó de expressão "e" lógico a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
"e" lógico de dois bits clássicos:
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> expr.logic_and(Clbit(), Clbit())
Binary(Binary.Op.LOGIC_AND, Var(<clbit 0>, Bool()), Var(<clbit 1>, Bool()), Bool())Parâmetros
Tipo de retorno
logic_or
qiskit.circuit.classical.expr.logic_or(left, right, /)
Cria um nó de expressão "ou" lógico a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
"Ou" lógico de dois bits clássicos
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> expr.logic_or(Clbit(), Clbit())
Binary(Binary.Op.LOGIC_OR, Var(<clbit 0>, Bool()), Var(<clbit 1>, Bool()), Bool())Parâmetros
Tipo de retorno
equal
qiskit.circuit.classical.expr.equal(left, right, /)
Cria um nó de expressão "igual" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Igualdade entre um registro clássico e um número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.equal(ClassicalRegister(3, "c"), 7)
Binary(Binary.Op.EQUAL, Var(ClassicalRegister(3, "c"), Uint(3)), Value(7, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
not_equal
qiskit.circuit.classical.expr.not_equal(left, right, /)
Cria um nó de expressão "não igual" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Desigualdade entre um registrador clássico e um número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.not_equal(ClassicalRegister(3, "c"), 7)
Binary(Binary.Op.NOT_EQUAL, Var(ClassicalRegister(3, "c"), Uint(3)), Value(7, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
less
qiskit.circuit.classical.expr.less(left, right, /)
Cria um nó de expressão "menor que" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Consulta se um registro clássico é menor que um número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.less(ClassicalRegister(3, "c"), 5)
Binary(Binary.Op.LESS, Var(ClassicalRegister(3, "c"), Uint(3)), Value(5, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
less_equal
qiskit.circuit.classical.expr.less_equal(left, right, /)
Cria um nó de expressão "menor que ou igual a" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores em nós Value se necessário.
Exemplos
Consulta se um registro clássico é menor ou igual a outro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.less_equal(ClassicalRegister(3, "a"), ClassicalRegister(3, "b"))
Binary(Binary.Op.LESS_EQUAL, Var(ClassicalRegister(3, "a"), Uint(3)), Var(ClassicalRegister(3, "b"), Uint(3)), Uint(3))Parâmetros
Tipo de retorno
greater
qiskit.circuit.classical.expr.greater(left, right, /)
Cria um nó de expressão "maior que" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Consulta se um registro clássico é maior que um número inteiro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.greater(ClassicalRegister(3, "c"), 5)
Binary(Binary.Op.GREATER, Var(ClassicalRegister(3, "c"), Uint(3)), Value(5, Uint(3)), Uint(3))Parâmetros
Tipo de retorno
greater_equal
qiskit.circuit.classical.expr.greater_equal(left, right, /)
Cria um nó de expressão "maior que ou igual a" a partir do valor fornecido, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Consulta se um registro clássico é maior ou igual a outro:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.greater_equal(ClassicalRegister(3, "a"), ClassicalRegister(3, "b"))
Binary(Binary.Op.GREATER_EQUAL, Var(ClassicalRegister(3, "a"), Uint(3)), Var(ClassicalRegister(3, "b"), Uint(3)), Uint(3))Parâmetros
Tipo de retorno
shift_left
qiskit.circuit.classical.expr.shift_left(left, right, /, type=None)
Cria um nó de expressão 'bitshift left' a partir dos dois valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores em nós Value se necessário.
Se type for fornecido, o operando left será coagido a ele (se possível).
Exemplos
Deslocar o valor de uma variável autônoma para a esquerda em algum valor:
>>> from qiskit.circuit.classical import expr, types
>>> a = expr.Var.new("a", types.Uint(8))
>>> expr.shift_left(a, 4)
Binary(Binary.Op.SHIFT_LEFT, Var(<UUID>, Uint(8), name='a'), Value(4, Uint(3)), Uint(8))Desloca um literal inteiro em um valor variável, forçando o tipo do literal:
>>> expr.shift_left(3, a, types.Uint(16))
Binary(Binary.Op.SHIFT_LEFT, Value(3, Uint(16)), Var(<UUID>, Uint(8), name='a'), Uint(16))Parâmetros
Tipo de retorno
shift_right
qiskit.circuit.classical.expr.shift_right(left, right, /, type=None)
Cria um nó de expressão 'bitshift right' a partir dos valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Se type for fornecido, o operando left será coagido a ele (se possível).
Exemplos
Deslocar o valor de um registrador clássico para a direita por algum valor:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.shift_right(ClassicalRegister(8, "a"), 4)
Binary(Binary.Op.SHIFT_RIGHT, Var(ClassicalRegister(8, "a"), Uint(8)), Value(4, Uint(3)), Uint(8))Parâmetros
Tipo de retorno
add
qiskit.circuit.classical.expr.add(left, right, /)
Cria um nó de expressão de adição a partir dos valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Adição de dois números de ponto flutuante:
>>> from qiskit.circuit.classical import expr
>>> expr.add(5.0, 2.0)
Binary(Binary.Op.ADD, Value(5.0, Float()), Value(2.0, Float()), Float())Adição de duas durações:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.add(Duration.dt(1000), Duration.dt(1000))
Binary(Binary.Op.ADD, Value(Duration.dt(1000), Duration()), Value(Duration.dt(1000), Duration()), Duration())Parâmetros
Tipo de retorno
sub
qiskit.circuit.classical.expr.sub(left, right, /)
Cria um nó de expressão de subtração a partir dos valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Exemplos
Subtração de dois números de ponto flutuante:
>>> from qiskit.circuit.classical import expr
>>> expr.sub(5.0, 2.0)
Binary(Binary.Op.SUB, Value(5.0, Float()), Value(2.0, Float()), Float())Subtração de duas durações:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.add(Duration.dt(1000), Duration.dt(1000))
Binary(Binary.Op.SUB, Value(Duration.dt(1000), Duration()), Value(Duration.dt(1000), Duration()), Duration())Parâmetros
Tipo de retorno
mul
qiskit.circuit.classical.expr.mul(left, right)
Cria um nó de expressão de multiplicação a partir dos valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Isso pode ser usado para multiplicar operandos numéricos do mesmo tipo ou para multiplicar um operando de duração por um operando numérico.
Exemplos
Multiplicação de dois números de ponto flutuante:
>>> from qiskit.circuit.classical import expr
>>> expr.mul(5.0, 2.0)
Binary(Binary.Op.MUL, Value(5.0, Float()), Value(2.0, Float()), Float())Multiplicação de uma duração por um float:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.mul(Duration.dt(1000), 0.5)
Binary(Binary.Op.MUL, Value(Duration.dt(1000), Duration()), Value(0.5, Float()), Duration())Parâmetros
Tipo de retorno
div
qiskit.circuit.classical.expr.div(left, right)
Cria um nó de expressão de divisão a partir dos valores fornecidos, resolvendo quaisquer conversões implícitas e elevando os valores para nós Value se necessário.
Isso pode ser usado para dividir operandos numéricos do mesmo tipo, para dividir um Duration operando por um operando numérico ou para dividir dois Duration que produz uma expressão do tipo Float.
Exemplos
Divisão de dois números de ponto flutuante:
>>> from qiskit.circuit.classical import expr
>>> expr.div(5.0, 2.0)
Binary(Binary.Op.DIV, Value(5.0, Float()), Value(2.0, Float()), Float())Divisão de duas durações:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.div(Duration.dt(10000), Duration.dt(1000))
Binary(Binary.Op.DIV, Value(Duration.dt(10000), Duration()), Value(Duration.dt(1000), Duration()), Float())Divisão de uma duração por um float:
>>> from qiskit.circuit import Duration
>>> from qiskit.circuit.classical import expr
>>> expr.div(Duration.dt(10000), 12.0)
Binary(Binary.Op.DIV, Value(Duration.dt(10000), Duration()), Value(12.0, types.Float()), Duration())Parâmetros
Tipo de retorno
Você pode indexar em números inteiros sem sinal e bit-likes usando outro número inteiro sem sinal de qualquer largura. Isso inclui operações de armazenamento, se o destino do índice for gravável.
index
qiskit.circuit.classical.expr.index(target, index, /)
Indexar no site target com o número inteiro fornecido index, elevando os valores em Value se necessário.
Isso pode ser usado como o destino de um Storese o target for um valor l.
Exemplos
Indexação em um registro clássico com um literal:
>>> from qiskit.circuit import ClassicalRegister
>>> from qiskit.circuit.classical import expr
>>> expr.index(ClassicalRegister(8, "a"), 3)
Index(Var(ClassicalRegister(8, "a"), Uint(8)), Value(3, Uint(2)), Bool())Parâmetros
Tipo de retorno
O método legado do Qiskit para especificar condições de igualdade para uso em condicionais é usar um tuplo duplo de um Clbit ou ClassicalRegister e um número inteiro. Isso representa uma condição de igualdade exata, e não há como especificar outras relações. A função auxiliar lift_legacy_condition() converte esse formato legado na nova sintaxe de expressão.
lift_legacy_condition
qiskit.circuit.classical.expr.lift_legacy_condition(condition, /)
Transforme uma condição de igualdade de duas tuplas legada em um novo estilo Expr.
Parâmetros
condition (tuple[qiskit.circuit.Clbit |qiskit.circuit.ClassicalRegister, int])
Tipo de retorno
Trabalhando com a árvore de expressões
Um consumidor típico da árvore de expressões deseja percorrer a árvore de forma recursiva, potencialmente com estado, agindo em cada nó de forma diferente, dependendo do seu tipo. Naturalmente, esse é um problema de despacho duplo; a lógica de "o que deve ser feito" provavelmente tem estado e os usuários devem ser livres para definir suas próprias operações, mas cada nó define "o que está sendo feito". Permitimos esse envio duplo fornecendo uma classe de visitante base para a árvore de expressões.
ExprVisitor
class qiskit.circuit.classical.expr.ExprVisitor
Bases: Generic[_T_co]
Classe base para visitantes da Expr árvore. As subclasses devem substituir qualquer um dos métodos do visit_* que puderem manipular e devem ser organizadas de forma que métodos inexistentes nunca sejam chamados.
visit_binary
visit_cast
visit_generic
visit_index
visit_stretch
visit_unary
visit_value
visit_var
Os consumidores da árvore de expressões devem fazer uma subclasse do visitante e substituir os métodos visit_* que desejam manipular. Todos os métodos não substituídos chamarão visit_generic()que, a menos que seja substituído, gerará um RuntimeError para garantir que você esteja ciente de que novos nós foram adicionados à árvore de expressões que você ainda não está manipulando.
Para a conveniência de visitantes simples que só precisam inspecionar as variáveis em uma expressão e não a estrutura geral, o método iterador iter_vars() é fornecido.
iter_vars
qiskit.circuit.classical.expr.iter_vars(node)
Obtém um iterador sobre os Var referenciados em qualquer nível no arquivo Expr.
Exemplos
Imprima o nome de cada ClassicalRegister encontrado:
from qiskit.circuit import ClassicalRegister
from qiskit.circuit.classical import expr
cr1 = ClassicalRegister(3, "a")
cr2 = ClassicalRegister(3, "b")
for node in expr.iter_vars(expr.bit_and(expr.bit_not(cr1), cr2)):
if isinstance(node.var, ClassicalRegister):
print(node.var.name)Parâmetros
node (Expr)
Tipo de retorno
Para iterar sobre todas as variáveis, inclusive as variáveis de extensão, o método iterador iter_identifiers() é fornecido.
iter_identifiers
qiskit.circuit.classical.expr.iter_identifiers(node)
Obter um iterador sobre o Var e Stretch referenciados em qualquer nível no nó Expr.
Exemplos
Imprima o nome de cada ClassicalRegister encontrado:
from qiskit.circuit import ClassicalRegister
from qiskit.circuit.classical import expr
cr1 = ClassicalRegister(3, "a")
cr2 = ClassicalRegister(3, "b")
for node in expr.iter_vars(expr.bit_and(expr.bit_not(cr1), cr2)):
if isinstance(node.var, ClassicalRegister):
print(node.var.name)Obtém um iterador sobre apenas os Var na expressão.
Parâmetros
node (Expr)
Tipo de retorno
Duas expressões podem ser comparadas quanto à igualdade estrutural direta usando o operador incorporado Python == . Em geral, porém, é possível comparar duas expressões de forma um pouco mais semântica, permitindo que os nós Var dentro delas estejam vinculados a diferentes descrições de localização de memória entre dois circuitos diferentes. Nesse caso, é possível usar structurally_equivalent() com duas funções "chave" adequadas para fazer a comparação.
structurally_equivalent
qiskit.circuit.classical.expr.structurally_equivalent(left, right, left_var_key=None, right_var_key=None)
Essas duas expressões têm exatamente a mesma estrutura de árvore, até alguma função-chave para os Var objetos?
Em outras palavras, essas duas expressões são exatamente as mesmas árvores, exceto que comparamos os campos Var.var chamando a função *_var_key apropriada neles e comparando a saída para igualdade. Essa função não permite nenhuma "equivalência" semântica, como afirmar que a == b é equivalente a b == a; a ordem de avaliação dos operandos poderia, em geral, fazer com que essa afirmação fosse falsa (considere as funções hipotéticas de extern que acessam o estado global).
Não há requisitos para as funções-chave, exceto o fato de que suas saídas devem ter métodos __eq__ gerais. Se uma função-chave retornar None, a variável será usada literalmente em seu lugar.
Parâmetros
- left (Expr) – um dos nós
Expr. - right (Expr) – o outro
Exprnó. - left_var_key (Callable[[Any], Any] | None) – um chamável cuja saída deve ser usada na comparação de
Var.varatributos. Se esse argumento forNoneou sua saída forNonepara uma determinada variável emleft, a variável será usada literalmente. - right_var_key (Callable[[Any], Any] | None) – o mesmo que
left_var_key, mas usado nas variáveis emrightem vez disso.
Tipo de retorno
Exemplos
Comparação de duas expressões para equivalência estrutural, sem remapeamento das variáveis. Elas são diferentes porque as diferentes Clbit instâncias se comparam de forma diferente:
>>> from qiskit.circuit import Clbit
>>> from qiskit.circuit.classical import expr
>>> left_bits = [Clbit(), Clbit()]
>>> right_bits = [Clbit(), Clbit()]
>>> left = expr.logic_and(expr.logic_not(left_bits[0]), left_bits[1])
>>> right = expr.logic_and(expr.logic_not(right_bits[0]), right_bits[1])
>>> expr.structurally_equivalent(left, right)
FalseComparando as mesmas duas expressões, mas desta vez usando funções de mapeamento que associam os bits a índices simples:
>>> left_key = {var: i for i, var in enumerate(left_bits)}.get
>>> right_key = {var: i for i, var in enumerate(right_bits)}.get
>>> expr.structurally_equivalent(left, right, left_key, right_key)
TrueAlgumas expressões têm locais de memória associados, e outras podem ser puramente temporárias. Você pode usar is_lvalue() para determinar se uma expressão tem um local de memória associado.
is_lvalue
qiskit.circuit.classical.expr.is_lvalue(node, /)
Retorna se essa expressão pode ser usada em posições de valor l, ou seja, se ela tem um local bem definido na memória, como um que possa ser gravado.
O fato de ser um valor l é necessário, mas não suficiente para que essa posição de memória seja gravável; é possível que um objeto maior que contenha essa posição de memória não permita a gravação a partir do escopo que tenta gravar nela. No entanto, isso seria uma propriedade de acesso do programa que a contém, e não uma propriedade inerente ao sistema de expressões.
Uma expressão constante nunca é um lvalue.
Exemplos
Os valores literais nunca são valores l; não há um local de memória associado (por exemplo) à constante 1:
>>> from qiskit.circuit.classical import expr
>>> expr.is_lvalue(expr.lift(2))
FalseVar são sempre valores l, pois sempre têm algum local de memória associado:
>>> from qiskit.circuit.classical import types
>>> from qiskit.circuit import Clbit
>>> expr.is_lvalue(expr.Var.new("a", types.Bool()))
True
>>> expr.is_lvalue(expr.lift(Clbit()))
TrueAtualmente, não há operações unárias ou binárias em variáveis que possam produzir uma expressão de valor l, mas é provável que, no futuro, seja adicionado algum tipo de operação de "indexação" que possa produzir valores l:
>>> a = expr.Var.new("a", types.Uint(8))
>>> b = expr.Var.new("b", types.Uint(8))
>>> expr.is_lvalue(a) and expr.is_lvalue(b)
True
>>> expr.is_lvalue(expr.bit_and(a, b))
FalseParâmetros
node (Expr)
Tipo de retorno
typing
qiskit.circuit.classical.types
Representação
O sistema de tipos da árvore de expressões é exposto por meio desse módulo. Isso está intrinsecamente vinculado ao sistema de expressão no módulo expr já que a maioria das expressões só pode ser entendida com o contexto dos tipos em que atuam.
Todos os tipos são herdados de uma classe base abstrata:
Tipo
class qiskit.circuit.classical.types.Type
Bases: object
Classe base raiz de todos os nós na árvore de tipos. O caso base nunca deve ser instanciado diretamente.
Isso não deve ser subclassificado pelos usuários; as subclasses formam os dados internos da representação das expressões, e não faz sentido adicionar mais fora do código da biblioteca do Qiskit.
Os tipos devem ser considerados objetos imutáveis, e você não deve alterá-los. É permitido reutilizar um Type que você extrai de outro objeto sem copiá-lo e, geralmente, essa é a melhor abordagem para o desempenho. Type são projetados para serem pequenas quantidades de dados, e é melhor apontar para a mesma instância dos dados sempre que possível, em vez de alocar no heap uma nova versão da mesma coisa. Sempre que possível, os construtores de classe retornarão instâncias de singleton para facilitar isso.
O tipo Bool representa Clbit e os literais True e False, o tipo Uint tipo representa ClassicalRegister e Python inteiros, o tipo Float representa Python floats e o tipo Duration representa uma duração para uso em operações de circuito com reconhecimento de tempo.
bool
class qiskit.circuit.classical.types.Bool
Bases: Type
O tipo booleano. Isso tem exatamente dois valores: True e False.
uint
class qiskit.circuit.classical.types.Uint(width)
Bases: Type
Um número inteiro sem sinal de largura de bit fixa.
Valor flutuante
class qiskit.circuit.classical.types.Float
Bases: Type
Um número de ponto flutuante de dupla precisão IEEE-754.
No futuro, isso também poderá ser usado para representar outros floats de largura fixa.
Duração
class qiskit.circuit.classical.types.Duration
Bases: Type
Um período de tempo, possivelmente negativo.
Trabalhando com tipos
Há algumas funções adicionais nesses tipos documentadas nas seções subsequentes. Espera-se que eles sejam usados apenas em manipulações da árvore de expressões; os usuários que estão criando expressões usando a interface de construção voltada para o usuário não devem precisar usá-los.
Ordenação parcial de tipos
O sistema de tipos é equipado com uma ordenação parcial, em que é interpretado como " é um subtipo estrito de ". Observe que a ordenação parcial é um subconjunto do gráfico direcionado que descreve as operações de conversão explícitas permitidas entre os tipos. A ordenação parcial define quando um tipo pode ser interpretado diretamente, sem perdas, como outro.
A interface de baixo nível para consultar a relação de subtipagem é a função order() função.
order
qiskit.circuit.classical.types.order(left, right, /)
Obtém a relação de ordenação entre os dois tipos como um valor de enumeração.
Exemplos
Compare dois Uint tipos de larguras diferentes:
>>> from qiskit.circuit.classical import types
>>> types.order(types.Uint(8), types.Uint(16))
Ordering.LESSCompare dois tipos que não têm ordenação entre si:
>>> types.order(types.Uint(8), types.Bool())
Ordering.NONEParâmetros
Tipo de retorno
O valor de retorno é uma enumeração Ordering que descreve qual relação de subtipagem existe, se houver, entre os dois tipos.
Ordem
class qiskit.circuit.classical.types.Ordering(*values)
Bases: Enum
Enumeração que lista as possíveis relações entre dois tipos. Os tipos têm apenas uma ordenação parcial, portanto, é possível que dois tipos não tenham nenhuma relação de subtipagem.
Observe que a relação de sub/supertipagem não é a mesma coisa que o fato de um tipo poder ser explicitamente convertido de um para outro.
Alguns métodos auxiliares são então definidos em termos desse nível baixo order() primitivo de baixo nível:
is_subtype
qiskit.circuit.classical.types.is_subtype(left, right, /, strict=False)
A relação é válida? Se não houver uma relação de ordem entre os dois tipos, o resultado será False. Se strict, então a igualdade também é proibida.
Exemplos
Verificar se um tipo é uma subclasse de outro:
>>> from qiskit.circuit.classical import types
>>> types.is_subtype(types.Uint(8), types.Uint(16))
TrueVerificar se um tipo é uma subclasse estrita de outro:
>>> types.is_subtype(types.Bool(), types.Bool())
True
>>> types.is_subtype(types.Bool(), types.Bool(), strict=True)
FalseParâmetros
Tipo de retorno
is_supertype
qiskit.circuit.classical.types.is_supertype(left, right, /, strict=False)
A relação é válida? Se não houver uma relação de ordem entre os dois tipos, o resultado será False. Se strict, então a igualdade também é proibida.
Exemplos
Verifica se um tipo é uma superclasse de outro:
>>> from qiskit.circuit.classical import types
>>> types.is_supertype(types.Uint(8), types.Uint(16))
FalseVerifica se um tipo é uma superclasse estrita de outro:
>>> types.is_supertype(types.Bool(), types.Bool())
True
>>> types.is_supertype(types.Bool(), types.Bool(), strict=True)
FalseParâmetros
Tipo de retorno
greater
qiskit.circuit.classical.types.greater(left, right, /)
Obtenha o maior dos dois tipos, supondo que haja uma relação de ordem entre eles. Tecnicamente, essa é uma versão um pouco restrita do conceito de "encontro" dos dois tipos, pois o valor de retorno deve ser uma das entradas. Na prática, no sistema de tipos, não há o conceito de um tipo "soma", portanto, o "encontro" existe se e somente se houver uma ordenação entre os dois tipos e for igual ao maior dos dois tipos.
Retorna
O maior dos dois tipos.
Aumentos
TypeError - se não houver relação de ordem entre os dois tipos.
Parâmetros
Tipo de retorno
Exemplos
Encontre o maior de dois Uint tipos:
>>> from qiskit.circuit.classical import types
>>> types.greater(types.Uint(8), types.Uint(16))
types.Uint(16)Conversão entre tipos
É comum precisar converter valores de um tipo em outro tipo. As regras de conversão para isso estão incorporadas no módulo types módulo. Você pode consultar os tipos de fundição usando cast_kind():
cast_kind
qiskit.circuit.classical.types.cast_kind(from_, to_, /)
Determine o tipo de conversão que é necessário para passar do tipo esquerdo para o tipo direito.
Exemplos
>>> from qiskit.circuit.classical import types
>>> types.cast_kind(types.Bool(), types.Bool())
<CastKind.EQUAL: 1>
>>> types.cast_kind(types.Uint(8), types.Bool())
<CastKind.IMPLICIT: 2>
>>> types.cast_kind(types.Bool(), types.Uint(8))
<CastKind.LOSSLESS: 3>
>>> types.cast_kind(types.Uint(16), types.Uint(8))
<CastKind.DANGEROUS: 4>Parâmetros
Tipo de retorno
Os valores de retorno dessa função são uma enumeração que explica os tipos de conversão que são permitidos do tipo esquerdo para o tipo direito.
Observe que as conversões entre Float e Uint são considerados perigosos em qualquer direção e devem ser feitos explicitamente.