OpenQASM 2
qiskit.qasm2
O Qiskit tem suporte para interoperação com os programas OpenQASM 2.0, tanto para análise em formatos Qiskit quanto para exportação de volta para OpenQASM 2.
OpenQASM 2 é uma linguagem simples e não é adequada para a serialização geral de objetos do Qiskit. Veja algumas discussões sobre alternativas abaixo, se é isso que você está procurando.
API de análise
Esse módulo contém duas funções públicas, ambas as quais criam um programa QuantumCircuit a partir de um programa OpenQASM 2. load() recebe um nome de arquivo, enquanto loads() recebe o próprio programa como uma cadeia de caracteres. Seus componentes internos são muito semelhantes, portanto, ambos oferecem praticamente a mesma API.
load
qiskit.qasm2.load(filename, *, include_path=('.',), include_input_directory='append', custom_instructions=(), custom_classical=(), strict=False)
Analise um programa OpenQASM 2 de um arquivo em um arquivo QuantumCircuit. O caminho fornecido deve ser codificado em ASCII ou UTF-8 e conter o programa OpenQASM 2.
O analisador interno de expressões clássicas é recursivo e lançará uma exceção RecursionError se alguma expressão exigir profundidade excessiva para ser avaliada. Essa profundidade máxima pode ser ajustada usando sys.setrecursionlimit(); o limite real é um décimo desse valor.
Parâmetros
- filename (str |PathLike) – O caminho para o arquivo
OpenQASM 2. - include_path (Iterable[str |PathLike]) – ordem dos diretórios a serem pesquisados ao avaliar
includeinstruções. - include_input_directory (Literal['append', 'prepend'] | None) – Se o diretório do arquivo de entrada deve ser adicionado a
include_pathe, em caso afirmativo, se deve ser acrescentado à pesquisa por último ou acrescentado previamente à pesquisa primeiro. PasseNonepara suprimir totalmente a adição desse diretório. - custom_instructions (Iterable[CustomInstruction]) – quaisquer construtores personalizados que devam ser utilizados para portas específicas ou instruções opacas durante a construção do circuito. Consulte “Como definir instruções personalizadas” para obter mais informações.
- custom_classical (Iterable[CustomClassical]) – quaisquer funções clássicas personalizadas que devam ser utilizadas durante a análise de expressões clássicas. Consulte “Especificação de funções clássicas personalizadas” para obter mais informações.
- strict (bool) – se deve ser executado em modo estrito.
Retorna
Um objeto de circuito que representa o mesmo programa OpenQASM 2.
Tipo de retorno
loads
qiskit.qasm2.loads(string, *, include_path=('.',), custom_instructions=(), custom_classical=(), strict=False)
Analise um programa OpenQASM 2 de uma string em um arquivo QuantumCircuit.
O analisador interno de expressões clássicas é recursivo e lançará uma exceção RecursionError se alguma expressão exigir profundidade excessiva para ser avaliada. Essa profundidade máxima pode ser ajustada usando sys.setrecursionlimit(); o limite real é um décimo desse valor.
Parâmetros
- string (str) – O programa OpenQASM 2 em uma cadeia de caracteres.
- include_path (Iterable[str |PathLike]) – ordem dos diretórios a serem pesquisados ao avaliar
includeinstruções. - custom_instructions (Iterable[CustomInstruction]) – quaisquer construtores personalizados que devam ser utilizados para portas específicas ou instruções opacas durante a construção do circuito. Consulte “Como definir instruções personalizadas” para obter mais informações.
- custom_classical (Iterable[CustomClassical]) – quaisquer funções clássicas personalizadas que devam ser utilizadas durante a análise de expressões clássicas. Consulte “Especificação de funções clássicas personalizadas” para obter mais informações.
- strict (bool) – se deve ser executado em modo estrito.
Retorna
Um objeto de circuito que representa o mesmo programa OpenQASM 2.
Tipo de retorno
Ambas as funções de carregamento também recebem um argumento include_path, que é um iterável de nomes de diretório a ser usado na busca de arquivos nos comandos include . Os diretórios são testados a partir do índice 0, e a primeira correspondência é usada. A importação qelib1.inc é tratada de forma especial; ela é sempre encontrada antes de procurar no caminho de inclusão e contém exatamente o conteúdo do documento que descreve a linguagem OpenQASM 2. As portas nesse arquivo de inclusão são mapeadas para objetos de porta de biblioteca de circuitos definidos pelo Qiskit.
Especificando instruções personalizadas
Você pode estender os componentes quânticos da linguagem OpenQASM 2 passando um iterável de informações sobre instruções personalizadas como o argumento custom_instructions. Em arquivos que tenham definições compatíveis para essas instruções, o constructor fornecido será usado no lugar de qualquer outra manipulação que qiskit.qasm2 teria sido feito. Essas instruções podem, opcionalmente, ser marcadas como builtin, o que faz com que elas não exijam uma declaração opaque ou gate , mas ignoram silenciosamente uma declaração compatível. De qualquer forma, é um erro fornecer uma instrução personalizada que tenha um número diferente de parâmetros ou qubits como uma instrução definida em um programa analisado. Cada elemento do argumento iterável deve ser uma classe de dados específica:
CustomInstruction
class qiskit.qasm2.CustomInstruction(name, num_params, num_qubits, constructor, builtin=False)
Bases: object
Informações sobre uma instrução personalizada que deve ser definida durante a análise.
Os campos name, num_params e num_qubits são autoexplicativos. O campo constructor deve ser um objeto chamável com a assinatura *args -> Instruction, em que cada um dos num_params args é um valor de ponto flutuante. A maioria das classes de portas integradas do Qiskit tem esse formato.
Há um campo final builtin . Isso é opcional e, se for definido como verdadeiro, fará com que a instrução seja definida e esteja disponível na análise, mesmo que não haja definição em nenhum arquivo OpenQASM 2 incluído.
Exemplos
Instrua o importador a usar as funções ECRGate e RZXGate do Qiskit para interpretar as declarações do gate que são conhecidas por terem sido criadas a partir desses mesmos objetos durante a exportação do OpenQASM 2:
from qiskit import qasm2
from qiskit.circuit import QuantumCircuit, library
qc = QuantumCircuit(2)
qc.ecr(0, 1)
qc.rzx(0.3, 0, 1)
qc.rzx(0.7, 1, 0)
qc.rzx(1.5, 0, 1)
qc.ecr(1, 0)
# This output string includes `gate ecr q0, q1 { ... }` and `gate rzx(p) q0, q1 { ... }`
# statements, since `ecr` and `rzx` are neither built-in gates nor in ``qelib1.inc``.
dumped = qasm2.dumps(qc)
# Tell the importer how to interpret the `gate` statements, which we know are safe
# because we controlled the input OpenQASM 2 source.
custom = [
qasm2.CustomInstruction("ecr", 0, 2, library.ECRGate),
qasm2.CustomInstruction("rzx", 1, 2, library.RZXGate),
]
loaded = qasm2.loads(dumped, custom_instructions=custom)Parâmetros
Isso pode ser particularmente útil ao tentar resolver ambiguidades nas convenções de fase global de um programa OpenQASM 2. Consulte OpenQASM 2 Convenções de fase para obter mais detalhes.
Especificando funções clássicas personalizadas
De forma semelhante às extensões quânticas acima, você também pode estender o processamento feito para expressões clássicas (argumentos para gates) passando um iterável para o argumento custom_classical para qualquer um dos carregadores. Isso requer o name (um identificador OpenQASM 2 válido), o número num_params de parâmetros necessários e um Python chamável que implemente a função. O chamável Python deve ser capaz de aceitar num_params argumentos de ponto flutuante posicional e deve retornar um ponto flutuante ou um número inteiro (que será convertido em um ponto flutuante). As funções incorporadas não podem ser substituídas.
CustomClassical
class qiskit.qasm2.CustomClassical(name, num_params, callable, /)
Bases: object
Informações sobre uma função clássica personalizada que deve ser definida em expressões matemáticas.
O callable fornecido deve ser uma função Python que recebe floats num_params e retorna um float. O nome é o identificador que faz referência a ele no programa OpenQASM 2. Isso não pode entrar em conflito com nenhum portão definido.
Modo estrito
Ambas as funções do carregador têm um modo "estrito" opcional. Por padrão, esse analisador é um pouco mais relaxado do que a especificação oficial: ele permite vírgulas finais em listas de parâmetros; pontos e vírgulas desnecessários (declaração vazia); a declaração da versão OPENQASM 2.0; a ser omitida; e algumas outras melhorias de qualidade de vida sem emitir nenhum erro. Você pode usar o modo de letra de especificação com strict=True.
API de exportação
Semelhante a outros módulos de serialização em Python, esse módulo oferece duas funções públicas: dump() e dumps()que recebem um QuantumCircuit e escrevem um programa OpenQASM 2 representativo em um objeto do tipo arquivo ou retornam uma string, respectivamente.
dump
qiskit.qasm2.dump(circuit, filename_or_stream, /)
Despeje um circuito como um programa OpenQASM 2 em um arquivo ou fluxo.
Parâmetros
- circuit (QuantumCircuit) – o
QuantumCircuita ser exportado. - filename_or_stream (PathLike |TextIOBase) – um objeto semelhante a um caminho (provavelmente um
stroupathlib.Path), ou um fluxo em modo texto já aberto.
Aumentos
QASM2ExportError - se o circuito não puder ser representado por OpenQASM 2.
dumps
qiskit.qasm2.dumps(circuit, /)
Exportar um circuito para um programa OpenQASM 2 em uma cadeia de caracteres.
Parâmetros
circuit (QuantumCircuit) – o QuantumCircuit a ser exportado.
Retorna
Uma cadeia de caracteres OpenQASM 2 que representa o circuito.
Aumentos
QASM2ExportError - se o circuito não puder ser representado por OpenQASM 2.
Tipo de retorno
Erros
Este módulo define um tipo de erro genérico que deriva de QiskitError que pode ser usado como uma captura quando você se preocupa especificamente com as falhas emitidas pela camada de interoperação.
QASM2Error
exception qiskit.qasm2.QASM2Error(*message)
Bases: QiskitError
Um erro geral gerado pela camada de interoperação do OpenQASM 2.
Defina a mensagem de erro.
Nos casos em que o lexer ou o analisador falhar devido a um arquivo OpenQASM 2 inválido, as funções de conversão gerarão um erro mais específico com uma mensagem explicando qual é a falha e em que parte do arquivo ela ocorreu.
QASM2ParseError
exception qiskit.qasm2.QASM2ParseError(*message)
Bases: QASM2Error
Um erro gerado devido a uma falha na análise de um arquivo OpenQASM 2.
Defina a mensagem de erro.
Quando os exportadores não conseguirem exportar um circuito, provavelmente porque ele tem uma estrutura que não pode ser representada por OpenQASM 2.0, eles também emitirão um erro personalizado.
QASM2ExportError
exception qiskit.qasm2.QASM2ExportError(*message)
Bases: QASM2Error
Um erro gerado devido a uma falha na conversão de um objeto Qiskit em um formulário OpenQASM 2.
Defina a mensagem de erro.
Exemplos
Exportando exemplos
Exportar um simples QuantumCircuit para uma cadeia de caracteres OpenQASM 2:
import qiskit.qasm2
from qiskit.circuit import QuantumCircuit
qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])
print(qiskit.qasm2.dumps(qc))OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];Escreve o mesmo QuantumCircuit em um determinado nome de arquivo:
qiskit.qasm2.dump(qc, "myfile.qasm")Da mesma forma, é possível usar instâncias gerais os.PathLike como nome de arquivo:
import pathlib
qiskit.qasm2.dump(qc, pathlib.Path.home() / "myfile.qasm")Também é possível despejar o texto em um fluxo já aberto:
import io
with io.StringIO() as stream:
qiskit.qasm2.dump(qc, stream)Exemplos de análise sintática
Usar loads() para importar um programa OpenQASM 2 em uma cadeia de caracteres para um arquivo QuantumCircuit:
import qiskit.qasm2
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0], q[1];
measure q -> c;
"""
circuit = qiskit.qasm2.loads(program)
circuit.draw() ┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1É possível fazer a mesma coisa se o programa estiver armazenado em um arquivo usando load() em vez disso, passando o nome do arquivo como um argumento:
import qiskit.qasm2
circuit = qiskit.qasm2.load("myfile.qasm")OpenQASM 2 podem incluir outros arquivos OpenQASM 2 por meio da instrução include . Você pode influenciar o caminho de pesquisa usado para localizar esses arquivos com o argumento include_path em ambos os comandos load() e loads(). Por padrão, somente o diretório de trabalho atual é pesquisado.
import qiskit.qasm2
program = """
include "other.qasm";
// ... and so on
"""
circuit = qiskit.qasm2.loads(program, include_path=("/path/to/a", "/path/to/b", "."))Somente para load() há um argumento extra include_input_directory, que pode ser usado para 'append', 'prepend' ou ignorar (None) o diretório do arquivo carregado no caminho de inclusão. Por padrão, esse diretório é anexado ao caminho de pesquisa, portanto, é tentado por último, mas você pode alterar isso.
import qiskit.qasm2
filenames = ["./subdirectory/a.qasm", "/path/to/b.qasm", "~/my.qasm"]
# Search the directory of each file before other parts of the include path.
circuits = [
qiskit.qasm2.load(filename, include_input_directory="prepend") for filename in filenames
]
# Override the include path, and don't search the directory of each file unless it's in the
# absolute path list.
circuits = [
qiskit.qasm2.load(
filename,
include_path=("/usr/include/qasm", "~/qasm/include"),
include_input_directory=None,
)
for filename in filenames
]Às vezes, você pode querer influenciar os objetos Gate que o importador emite para determinadas instruções nomeadas. As portas definidas pela instrução include "qelib1.inc"; serão automaticamente associadas a uma porta adequada da biblioteca de circuitos Qiskit, mas você pode estender isso:
from qiskit.circuit import Gate
from qiskit.qasm2 import loads, CustomInstruction
class MyGate(Gate):
def __init__(self, theta):
super().__init__("my", 2, [theta])
class Builtin(Gate):
def __init__(self):
super().__init__("builtin", 1, [])
program = """
opaque my(theta) q1, q2;
qreg q[2];
my(0.5) q[0], q[1];
builtin q[0];
"""
customs = [
CustomInstruction(name="my", num_params=1, num_qubits=2, constructor=MyGate),
# Setting 'builtin=True' means the instruction doesn't require a declaration to be usable.
CustomInstruction("builtin", 0, 1, Builtin, builtin=True),
]
circuit = loads(program, custom_instructions=customs)Da mesma forma, você pode adicionar novas funções clássicas usadas durante a descrição dos argumentos para as portas, tanto no corpo principal do programa (que são dobradas de forma constante) quanto nos corpos das portas definidas (que são computadas sob demanda). Aqui, fornecemos uma versão Python de atan2(y, x), que matematicamente é , mas que lida corretamente com quadrantes angulares e infinitos, e uma função personalizada add_one :
import math
from qiskit.qasm2 import loads, CustomClassical
program = """
include "qelib1.inc";
qreg q[2];
rx(atan2(pi, 3 + add_one(0.2))) q[0];
cx q[0], q[1];
"""
def add_one(x):
return x + 1
customs = [
# `atan2` takes two parameters, and `math.atan2` implements it.
CustomClassical("atan2", 2, math.atan2),
# Our `add_one` takes only one parameter.
CustomClassical("add_one", 1, add_one),
]
circuit = loads(program, custom_classical=customs)OpenQASM Convenções de 2 fases
Como linguagem, o OpenQASM 2 não tem uma maneira de especificar a fase global de um programa completo, nem de definições de portas específicas. Isso significa que os analisadores da linguagem podem interpretar determinadas portas com uma fase global diferente da esperada. Por exemplo, a biblioteca padrão de fato de OpenQASM 2 qelib1.inc contém definições de u1 e rz da seguinte forma:
gate u1(lambda) q {
U(0, 0, lambda) q;
}
gate rz(phi) a {
u1(phi) a;
}Em outras palavras, rz parece ser um alias direto de u1. No entanto, a interpretação de u1 é especificada na equação (3) do documento que descreve a linguagem como
onde o símbolo denota equivalência somente até uma fase global. Ao analisar OpenQASM 2, precisamos escolher como lidar com uma distinção entre esses portões; u1 é definido na prosa como sendo diferente por uma fase de rz, mas a linguagem não foi projetada para representar isso.
A posição padrão do Qiskit é interpretar um uso da biblioteca padrão rz usando RZGatee um uso de u1 como usando a distinção de fase U1Gate. Se desejar usar as convenções de fase mais implícitas por uma interpretação direta das instruções gate no arquivo de cabeçalho, você poderá usar CustomInstruction para substituir a forma como o Qiskit constrói o circuito.
Para o padrão qelib1.inc include, há apenas um ponto de diferença e, portanto, a substituição necessária para mudar sua convenção de fase é:
from qiskit import qasm2
from qiskit.circuit.library import PhaseGate
from qiskit.quantum_info import Operator
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[1];
rz(pi / 2) q[0];
"""
custom = [
qasm2.CustomInstruction("rz", 1, 1, PhaseGate),
]Isso usará a classe PhaseGate para representar a instrução rz , que é igual (incluindo a fase) a U1Gate:
Operator(qasm2.loads(program, custom_instructions=custom))Operator([[1.000000e+00+0.j, 0.000000e+00+0.j],
[0.000000e+00+0.j, 6.123234e-17+1.j]],
input_dims=(2,), output_dims=(2,))Compatibilidade com versões anteriores
QuantumCircuit.from_qasm_str() e from_qasm_file() usado para fazer alguns acréscimos sobre a especificação bruta. Originalmente, o Qiskit tentou usar o OpenQASM 2 como um tipo de formato de serialização e expandiu seu comportamento à medida que o Qiskit se expandia. O novo analisador, com todos os seus padrões, implementa a especificação de forma mais rigorosa.
Em particular, nos importadores de legado:
-
o include_path é eficaz:
<qiskit>/qasm/libs, em que<qiskit>é a raiz do pacoteqiskitinstalado;- O diretório atualmente em funcionamento.
-
há instruções adicionais definidas em
qelib1.inc:csx a, bControlado gate, correspondente a
CSXGate.cu(theta, phi, lambda, gamma) c, tA versão de quatro parâmetros de um controle- , correspondente a
CUGate.rxx(theta) a, bRotação de dois qubits em torno do eixo , correspondente a
RXXGate.rzz(theta) a, bRotação de dois qubits em torno do eixo , correspondente a
RZZGate.rccx a, b, cA porta com controle duplo, mas com diferenças de fase relativas em relação à porta Toffoli padrão. Isso deve corresponder ao Qiskit gate
RCCXGatemas o conversor legado não produziria de fato esse tipo.rc3x a, b, c, dA porta com controle triplo, mas com diferenças de fase relativas em relação à definição padrão. Corresponde a
RC3XGate.c3x a, b, c, dA porta com controle triplo, correspondente a
C3XGate.c3sqrtx a, b, c, dA porta com controle triplo, correspondente a
C3SXGate.c4x a, b, c, d, eO portão de controle quádruplo .., correspondente a
C4XGate. -
se alguma definição de
opaqueougatefoi dada para o nomedelay, eles tentam emitir umaDelayem cada chamada. Para funcionar, espera-se uma definição compatível comopaque delay(t) q;, em que o tempoté dado em unidades dedt. O importador gerará erros na construção se não houver exatamente um parâmetro e um qubit, ou se o parâmetro não tiver valor inteiro. -
as funções adicionais de calculadora científica
asin,acoseatanestão disponíveis. -
a gramática analisada é efetivamente a mesma que o modo estrito dos novos importadores.
Você pode emular esse comportamento em load() e loads() configurando include_path adequadamente (tente inspecionar a variável qiskit.__file__ para encontrar o local instalado) e passando uma lista de instâncias de CustomInstruction para cada uma das portas personalizadas que lhe interessam. Para facilitar as coisas, disponibilizamos três tuplas, cada uma contendo um componente de uma configuração que é equivalente ao comportamento do conversor legado do Qiskit.
qiskit.qasm2.LEGACY_CUSTOM_INSTRUCTIONS
Uma tupla que contém as custom_instructions extras que os conversores incorporados legados do Qiskit usaram se qelib1.inc estiver incluído e houver qualquer definição de uma instrução delay . Todas as portas na versão impressa de qelib1.inc e delay exigem que uma declaração compatível esteja presente no programa OpenQASM 2, mas as adições herdadas do Qiskit são todas marcadas como builtins, pois não estão presentes em nenhum arquivo de inclusão que esse analisador vê.
qiskit.qasm2.LEGACY_CUSTOM_CLASSICAL
Uma tupla que contém as funções customizadas_clássicas adicionais que os conversores incorporados legados do Qiskit usam além daquelas especificadas pelo documento. Essas são as três funções trigonométricas inversas básicas: , e .
qiskit.qasm2.LEGACY_INCLUDE_PATH
Uma tupla que contém o include_path exato usado pelo conversor Qiskit legado.
Em todas as portas definidas na versão legada do Qiskit do qelib1.inc e na instrução delay , não importa como as portas são de fato definidas e usadas, o importador legado sempre tentará gerar seus objetos personalizados para elas. Isso pode resultar em erros durante a construção do circuito, mesmo após uma análise bem-sucedida. Não há como emular esse comportamento problemático com o qiskit.qasm2somente uma instrução include "qelib1.inc"; ou o argumento custom_instructions pode fazer com que as instruções integradas do Qiskit sejam usadas, e as assinaturas dessas instruções são iguais.
Circuitos importados com load() e loads() com as configurações de compatibilidade com o legado acima devem ser iguais aos criados pelo importador legado do Qiskit, desde que não sejam definidas portas de usuário que não sejamqelib1.inc . As portas definidas pelo usuário são tratadas de forma ligeiramente diferente no novo importador e, embora devam ter campos definition equivalentes em uma inspeção, este módulo usa uma classe personalizada para carregar preguiçosamente a definição quando ela é solicitada (como a maioria dos objetos do Qiskit), em vez de criá-la avidamente durante a análise. As regras de comparação do Qiskit para portas verão esses dois objetos como desiguais, embora qualquer passagem transpile() para um backend específico deva produzir os mesmos circuitos de saída.
Alternativas
Os componentes do analisador deste módulo começaram como um pacote PyPI separado: qiskit-qasm2. Esse pacote na versão 0.5.3 foi vendido para o Qiskit Terra 0.24. Quaisquer alterações subsequentes entre os dois pacotes podem não ser necessariamente mantidas em sincronia.
Há uma versão mais recente da especificação OpenQASM, a versão 3.0, que é descrita em https://openqasm.com. Isso inclui muito mais recursos para programação clássica de alto nível. O Qiskit já tem algum suporte rudimentar para OpenQASM 3; consulte qiskit.qasm3 para isso.
OpenQASM 2 não é uma linguagem de serialização adequada para o Qiskit QuantumCircuit. Esse módulo é fornecido para fins de interoperabilidade, não como um formato de serialização geral. Se for isso que você precisa, considere usar qiskit.qpy em vez disso.